package com.yy.device.boot.protocol;

import cn.hutool.core.util.HexUtil;
import com.yy.device.constant.DeviceConstant;
import com.yy.device.enums.DeviceDataEnum;
import com.yy.device.enums.DeviceFunctionEnum;
import com.yy.device.enums.DeviceHeadEnum;
import com.yy.util.BitConverter;
import com.yy.util.Crc16Utils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.util.ReferenceCountUtil;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;

/**
 * 任务消息
 *
 * @author zhiqiang.sun
 * @date 2022/06/21
 */
@Slf4j
@Data
@EqualsAndHashCode(callSuper = true)
public class TaskMessage extends Message {

    private byte head;
    private byte version;
    private short length;
    private Long taskId;
    private byte address;
    private DeviceFunctionEnum deviceFunctionEnum;
    private short devicePointCode;
    private DeviceDataEnum deviceDataEnum;
    private short crcMod;
    private short crc;
    private byte end;

    public static TaskMessage createSend(DeviceFunctionEnum deviceFunctionEnum
            , DeviceDataEnum deviceDataEnum
            , short devicePointCode
            , Long taskId) {
        TaskMessage taskMessage = new TaskMessage();
        taskMessage.setHead(BitConverter.getBytes(DeviceHeadEnum.REGISTER_TASK.getType())[0]);
        taskMessage.setVersion(DeviceConstant.VERSION);
        taskMessage.setLength(DeviceConstant.TASK_LENGTH);
        taskMessage.setTaskId(taskId);
        taskMessage.setAddress(DeviceConstant.ADDRESS);
        taskMessage.setDeviceFunctionEnum(deviceFunctionEnum);
        taskMessage.setDevicePointCode(devicePointCode);
        taskMessage.setDeviceDataEnum(deviceDataEnum);
        taskMessage.setEnd(DeviceConstant.END);
        return taskMessage;
    }

    public static TaskMessage createSend(DeviceFunctionEnum deviceFunctionEnum
            , DeviceDataEnum deviceDataEnum
            , short devicePointCode
    ) {

        return createSend(deviceFunctionEnum, deviceDataEnum, devicePointCode, null);
    }

    @Override
    public void encode(ByteBuf byteBuf) {
        ByteBuf buffer = Unpooled.buffer();
        ByteBuf bufferMod = Unpooled.buffer();
        try {
            buffer.writeByte(this.getHead());
            buffer.writeByte(this.getVersion());
            buffer.writeShortLE(this.getLength());
            buffer.writeLongLE(this.getTaskId());

            bufferMod.writeByte(this.getAddress());
            bufferMod.writeByte(this.getDeviceFunctionEnum().getType());
            bufferMod.writeShort(this.getDevicePointCode());
            bufferMod.writeShort(this.getDeviceDataEnum().getType());
            byte[] bytes = new byte[bufferMod.readableBytes()];
            bufferMod.readBytes(bytes);
            String s = Crc16Utils.byteTo16String(Crc16Utils.getData(bytes));
            bufferMod.writeBytes(HexUtil.decodeHex(s));
            buffer.writeBytes(bufferMod);

            bytes = new byte[buffer.readableBytes()];
            buffer.readBytes(bytes);
            s = Crc16Utils.byteTo16String(Crc16Utils.getData(bytes));
            byteBuf.writeBytes(HexUtil.decodeHex(s));
            byteBuf.writeByte(this.getEnd());
        } catch (Exception e) {
            log.error("taskMessage encoding error", e);
        } finally {
            ReferenceCountUtil.release(buffer);
            ReferenceCountUtil.release(bufferMod);
        }
    }

    @Override
    public void decode(ByteBuf byteBuf) {
        this.setTaskId(byteBuf.readLongLE());
        this.setAddress(byteBuf.readByte());
        this.setDeviceFunctionEnum(DeviceFunctionEnum.getEnumByType(byteBuf.readByte() & 0xff));
        this.setDevicePointCode(byteBuf.readShortLE());
        this.setDeviceDataEnum(DeviceDataEnum.getEnumByType(byteBuf.readShortLE()));
        this.setCrcMod(byteBuf.readShortLE());
        this.setCrcMod(byteBuf.readShortLE());
    }
}
